// fft.h

// Copyright (C) 2010  traxex

// Author: 	traxex <traxex@yahoo.cn>
// Created: 	17 May 2010
// Version: 	1.0
#pragma once

namespace traxex{
namespace cuda{
namespace {
    int FFT_BATCH = 32;
}

template<typename F, typename T>struct CufftTypeHelper;
template<>struct CufftTypeHelper<float,cfloat>		{ enum{TYPE=CUFFT_R2C}; };
template<>struct CufftTypeHelper<cfloat,float>		{ enum{TYPE=CUFFT_C2R};	};
template<>struct CufftTypeHelper<cfloat,cfloat>		{ enum{TYPE=CUFFT_C2C};	};
template<>struct CufftTypeHelper<double,cdouble>	{ enum{TYPE=CUFFT_D2Z};	};
template<>struct CufftTypeHelper<cdouble,double>	{ enum{TYPE=CUFFT_Z2D};	};
template<>struct CufftTypeHelper<cdouble,cdouble>	{ enum{TYPE=CUFFT_Z2Z};	};

inline cufftResult cufftExec( cufftHandle p, float *in, cfloat *out, int direction){
    return cufftExecR2C( p, (cufftReal*)in, (cufftComplex*)out);
}
inline cufftResult cufftExec( cufftHandle p, cfloat *in, float *out, int direction){
    return cufftExecC2R( p, (cufftComplex*)in, (cufftReal*)out);
}
inline cufftResult cufftExec( cufftHandle p, cfloat *in, cfloat *out, int direction){
    return cufftExecC2C( p, (cufftComplex*)in, (cufftComplex*)out, direction);
}

inline cufftResult cufftExec( cufftHandle p, double *in, cdouble *out, int direction){
    return cufftExecD2Z( p, (cufftDoubleReal*)in, (cufftDoubleComplex*)out);
}
inline cufftResult cufftExec( cufftHandle p, cdouble *in, double *out, int direction){
    return cufftExecZ2D( p, (cufftDoubleComplex*)in, (cufftDoubleReal*)out);
}
inline cufftResult cufftExec( cufftHandle p, cdouble *in, cdouble *out, int direction){
    return cufftExecZ2Z( p, (cufftDoubleComplex*)in, (cufftDoubleComplex*)out, direction);
}


template<class F, class T> void fftbase( T *out, F *in, size_t length, int direction, int n=1){
    cufftHandle plan;
    if( n >= FFT_BATCH){
        _safecall( cufftPlan1d ( &plan, length, (cufftType)CufftTypeHelper<F,T>::TYPE, FFT_BATCH));
        for( int i = 0; i < n/FFT_BATCH; ++i, in+=FFT_BATCH, out+=FFT_BATCH)
            _safecall( cufftExec( plan,  in, out, direction ));
        _safecall( cufftDestroy ( plan ));		
    }
    if( n%FFT_BATCH != 0){
        _safecall( cufftPlan1d ( &plan, length, (cufftType)CufftTypeHelper<F,T>::TYPE, n%FFT_BATCH));
        _safecall( cufftExec( plan,  in, out, direction ));
        _safecall( cufftDestroy ( plan ));		
    }
}	    

}
}
